package pku;

import java.util.HashSet;
import java.util.Set;

/**
 * 一个Key-Value的实现
 */
public class DefaultKeyValue implements KeyValue{
    String[] keys;

    byte[][] values;

    int num;

    byte[] pos;

    public DefaultKeyValue(int cap) {
        this.keys = new String[cap];
        this.values = new byte[cap][];
        this.pos = new byte[cap];
        this.num = 0;
    }

    public KeyValue put(String key, byte[] value) {

        keys[num] = key;
        pos[num] = (byte) getPos(key);
        values[num++] = value;
        return this;
    }


    public KeyValue put(String key, int a) {
        put(key, new byte[] { (byte) (a >> 24 & 0xff), (byte) (a >> 16 & 0xff), (byte) (a >> 8 & 0xff),
                (byte) (a & 0xff) });
        return this;
    }


    public KeyValue put(String key, long value) {
        put(key, toBytes(value));
        return this;
    }


    public KeyValue put(String key, double value) {
        put(key, toBytes(value));
        return this;
    }


    public KeyValue put(String key, String value) {
        put(key, value.getBytes());
        return this;
    }


    public int getInt(String key) {
        byte[] b = get(key);
        return (((b[0]) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | ((b[3] & 0xff)));
    }


    public long getLong(String key) {
        return toLong(get(key));
    }


    public double getDouble(String key) {
        byte[] bytes = get(key);
        return toDouble(bytes);
    }


    public String getString(String key) {
        byte[] bytes = get(key);
        return bytes == null ? null : new String(bytes);
    }

    private byte[] get(String key) {
        for (int i = 0; i < num; i++) {
            if (keys[i].equals(key)) {
                return values[i];
            }
        }
        return null;
    }


    public Set<String> keySet() {
        Set<String> set = new HashSet<>();
        for (int i = 0; i < num; i++) {
            set.add(keys[i]);
        }
        return set;
    }

    public int size() {
        return num;
    }


    public boolean containsKey(String key) {
        for (int i = 0; i < num; i++) {
            if (keys[i].equals(key)) {
                return true;
            }
        }
        return false;
    }

    private static long toLong(byte[] bs) {
        return ((((long) bs[0]) << 56) | (((long) bs[1] & 0xff) << 48) | (((long) bs[2] & 0xff) << 40)
                | (((long) bs[3] & 0xff) << 32) | (((long) bs[4] & 0xff) << 24) | (((long) bs[5] & 0xff) << 16)
                | (((long) bs[6] & 0xff) << 8) | (((long) bs[7] & 0xff)));
    }

    private static byte[] toBytes(long a) {
        return new byte[] { (byte) (a >> 56 & 0xff), (byte) (a >> 48 & 0xff), (byte) (a >> 40 & 0xff),
                (byte) (a >> 32 & 0xff), (byte) (a >> 24 & 0xff), (byte) (a >> 16 & 0xff), (byte) (a >> 8 & 0xff),
                (byte) (a & 0xff) };
    }

    private static byte[] toBytes(double a) {
        return toBytes(Double.doubleToRawLongBits(a));
    }

    private static double toDouble(byte[] bs) {
        return Double.longBitsToDouble(toLong(bs));
    }

    public void clear() {
        this.num = 0;
    }

    public int getPos(String key){
        if (key.equals(MessageHeader.MESSAGE_ID)) return 0;
        if (key.equals(MessageHeader.TOPIC)) return 1;
        if (key.equals(MessageHeader.BORN_TIMESTAMP)) return 2;
        if (key.equals(MessageHeader.BORN_HOST)) return 3;
        if (key.equals(MessageHeader.STORE_TIMESTAMP)) return 4;
        if (key.equals(MessageHeader.STORE_HOST)) return 5;
        if (key.equals(MessageHeader.START_TIME)) return 6;
        if (key.equals(MessageHeader.STOP_TIME)) return 7;
        if (key.equals(MessageHeader.TIMEOUT)) return 8;
        if (key.equals(MessageHeader.PRIORITY)) return 9;
        if (key.equals(MessageHeader.RELIABILITY)) return 10;
        if (key.equals(MessageHeader.SEARCH_KEY)) return 11;
        if (key.equals(MessageHeader.SCHEDULE_EXPRESSION)) return 12;
        if (key.equals(MessageHeader.SHARDING_KEY)) return 13;
        if (key.equals(MessageHeader.SHARDING_PARTITION)) return 14;
        if (key.equals(MessageHeader.TRACE_ID)) return 15;
        return -1;
    }

}
